#include <vector>
#ifndef _WINDOWS
#include "mermaid.h"
#endif
#include "Panels.h"

using xxship::Panels;


/** Constructor. */
Panels::Panels()
  : m_panels()
{}



/** Copy-constructor. */
Panels::Panels(Panels const& other)
  : m_panels(other.m_panels)
{}



/** Destructor. */
Panels::~Panels()
{}



/** Copy assignment operator. */
Panels const& Panels::operator=(Panels const& other)
{
  new (this) Panels(other);
  return *this;
}



/** Erase all panels. */
void Panels::clear()
{
  m_panels.clear();
}



/** Number of panels. */
int Panels::getNumberOfPanels() const
{
  return static_cast<int>(m_panels.size());
}



/** Get a panel. */
xxship::Panel const& Panels::getPanel(int i) const
{
#ifdef _DEBUG
  if (i < 0 || i > getNumberOfPanels()) {
    throw mml::IndexOutOfBounds();
  }
#endif
  return m_panels[i];
}



/** Add a panel. */
void Panels::addPanel(xxship::Panel const& panel)
{
  m_panels.push_back(panel);
}



Panels Panels::createReducedPanels(mml::Planed const& plane) const
{
  Panels reduced;

  for (int i = 0; i < getNumberOfPanels(); ++i) {
    Panel reducedPanel = getPanel(i).createReducedPanel(plane);
    if (reducedPanel.getNumberOfVertices() > 2) {
      reduced.addPanel(reducedPanel);
    }
  }

  return reduced;
}



/** Rotate the panels. */
void Panels::rotate(mml::Matrix3d const& R)
{
  for (int i = 0; i < getNumberOfPanels(); ++i) {
    m_panels[i].rotate(R);
  }
}



/** Transform the panels. */
void Panels::translate(mml::Vector3d const& translation)
{
  for (int i = 0; i < getNumberOfPanels(); ++i) {
    m_panels[i].translate(translation);
  }
}



/** Maximum x-coordinate of these panels. */
double Panels::getMaxX() const
{
  double xmax = -DBL_MAX;
  for (int i = 0; i < getNumberOfPanels(); ++i) {
    double candidate = getPanel(i).getMaxX();
    if (candidate > xmax) {
      xmax = candidate;
    }
  }
  return xmax;
}



/** Minimum x-coordinate of these panels. */
double Panels::getMinX() const
{
  double xmin = DBL_MAX;
  for (int i = 0; i < getNumberOfPanels(); ++i) {
    double candidate = getPanel(i).getMinX();
    if (candidate < xmin) {
      xmin = candidate;
    }
  }
  return xmin;
}



/** Maximum y-coordinate of these panels. */
double Panels::getMaxY() const
{
  double ymax = -DBL_MAX;
  for (int i = 0; i < getNumberOfPanels(); ++i) {
    double candidate = getPanel(i).getMaxY();
    if (candidate > ymax) {
      ymax = candidate;
    }
  }
  return ymax;
}



/** Minimum y-coordinate of these panels. */
double Panels::getMinY() const
{
  double ymin = DBL_MAX;
  for (int i = 0; i < getNumberOfPanels(); ++i) {
    double candidate = getPanel(i).getMinY();
    if (candidate < ymin) {
      ymin = candidate;
    }
  }
  return ymin;
}



/** Maximum z-coordinate of these panels. */
double Panels::getMaxZ() const
{
  double zmax = -DBL_MAX;
  for (int i = 0; i < getNumberOfPanels(); ++i) {
    double candidate = getPanel(i).getMaxZ();
    if (candidate > zmax) {
      zmax = candidate;
    }
  }
  return zmax;
}



/** Minimum z-coordinate of these panels. */
double Panels::getMinZ() const
{
  double zmin = DBL_MAX;
  for (int i = 0; i < getNumberOfPanels(); ++i) {
    double candidate = getPanel(i).getMinZ();
    if (candidate < zmin) {
      zmin = candidate;
    }
  }
  return zmin;
}


/** Bounding box in XY-plane */
void Panels::getBoundingBox(double* pMinX, double* pMinY, double* pMaxX, double* pMaxY) const
{
    *pMinX =  DBL_MAX;
    *pMinY =  DBL_MAX;
    *pMaxX = -DBL_MAX;
    *pMaxY = -DBL_MAX;

    int n = getNumberOfPanels();
    for (int i = 0; i < n; ++i)
    {
        double minX, maxX, minY, maxY;
        getPanel(i).getBoundingBox(&minX, &minY, &maxX, &maxY);
        if (minX < *pMinX)
        {
            *pMinX = minX;
        }
        if (maxX > *pMaxX)
        {
            *pMaxX = maxX;
        }
        if (minY < *pMinY)
        {
            *pMinY = minY;
        }
        if (maxY > *pMaxY)
        {
            *pMaxY = maxY;
        }
    }
}


